﻿using Serilog;
using Serilog.Events;
using Serilog.Sinks.MSSqlServer;
using System.Collections.ObjectModel;
using System.Data;

namespace QuartzServices.Web.Extensions
{
    /// <summary>
    /// 配置日志
    /// </summary>
    public static class SerilogSetup
    {

        private static readonly string logDebug = $"{AppDomain.CurrentDomain.BaseDirectory}\\Log\\Debug\\debug.log";
        private static readonly string logInfo = $"{AppDomain.CurrentDomain.BaseDirectory}\\Log\\Info\\info.log";
        private static readonly string logWarn = $"{AppDomain.CurrentDomain.BaseDirectory}\\Log\\Warn\\warn.log";
        private static readonly string logError = $"{AppDomain.CurrentDomain.BaseDirectory}\\Log\\Error\\error.log";
        private static readonly string logFatal = $"{AppDomain.CurrentDomain.BaseDirectory}\\Log\\Fatal\\fatal.log";

        private static readonly string logTemplate =
@"时闻:{Timestamp:yyyy-MM-dd HH:mm:ss.fff}
日志等级:{Level}
线程ID:{ThreadId}
文件路径:{FilePath}
所在类:{SourceContext}
方法名:{MemberName}
行号:{LineNumber}
日志信息:{Message}
异常信息:{Exception}{NewLine}{NewLine}";

        public static void AddSerilog(this ConfigureHostBuilder builder, IConfiguration configuration)
        {
            builder.UseSerilog((context, logger) =>
            {
                // 重写打印级别
//                logger.MinimumLevel.Override("Microsoft.EntityFrameworkCore", LogEventLevel.Error);
                logger.MinimumLevel.Override("System.Net.Http.HttpClient", LogEventLevel.Error);
                logger.MinimumLevel.Override("Microsoft.AspNetCore", LogEventLevel.Error);

                logger.MinimumLevel.Debug();
                logger.Enrich.FromLogContext();
                logger.Enrich.WithThreadId();

                // TODO：如果项目部署到IIS上不需要打印到控制台
                // 打印到控制台
                logger.WriteTo.Logger(lg => lg.WriteTo.Async(a => a.Console(outputTemplate: logTemplate)));

                // 按日志级别打印到不同文件 
                logger.WriteTo.Logger(lg => lg.Filter.ByIncludingOnly(p => p.Level == LogEventLevel.Debug).WriteTo.Async(a => a.File(logDebug, rollingInterval: RollingInterval.Hour, outputTemplate: logTemplate)));
                logger.WriteTo.Logger(lg => lg.Filter.ByIncludingOnly(p => p.Level == LogEventLevel.Information).WriteTo.Async(a => a.File(logInfo, rollingInterval: RollingInterval.Hour, outputTemplate: logTemplate)));
                logger.WriteTo.Logger(lg => lg.Filter.ByIncludingOnly(p => p.Level == LogEventLevel.Warning).WriteTo.Async(a => a.File(logWarn, rollingInterval: RollingInterval.Hour, outputTemplate: logTemplate)));
                logger.WriteTo.Logger(lg => lg.Filter.ByIncludingOnly(p => p.Level == LogEventLevel.Error).WriteTo.Async(a => a.File(logError, rollingInterval: RollingInterval.Hour, outputTemplate: logTemplate)));
                logger.WriteTo.Logger(lg => lg.Filter.ByIncludingOnly(p => p.Level == LogEventLevel.Fatal).WriteTo.Async(a => a.File(logFatal, rollingInterval: RollingInterval.Hour, outputTemplate: logTemplate)));

                // 数据库相关信息
                var sqlServerOptions = new MSSqlServerSinkOptions
                {
                    TableName = configuration["Serilog:TableName"],
                    BatchPostingLimit = configuration.GetValue<int>("Serilog:BatchPostingLimit"),
                    // 不要用Serilog框架生成日志表，要用EFCore生成
                    AutoCreateSqlTable = false,
                    SchemaName = configuration["Serilog:SchemaName"]
                };

                // 自定义列
                var columnOptions = new ColumnOptions();
                // 删除自带Id列
                columnOptions.Store.Remove(StandardColumn.Id);

                // 如果属性被保存到其他列中，则将其排除在属性列之外
                columnOptions.Properties.ExcludeAdditionalProperties = true;
                // 添加自定义列
                columnOptions.AdditionalColumns = new Collection<SqlColumn>(){
                    new SqlColumn { DataType = SqlDbType.NVarChar, ColumnName = "SourceContext" },
                    new SqlColumn { DataType = SqlDbType.NVarChar, DataLength=10, ColumnName= "ThreadId"},
                    new SqlColumn { DataType = SqlDbType.NVarChar, DataLength=300, ColumnName= "FilePath"},
                    new SqlColumn { DataType = SqlDbType.NVarChar, DataLength=50, ColumnName= "MemberName"},
                    new SqlColumn { DataType = SqlDbType.NVarChar, DataLength=10, ColumnName= "LineNumber"}
                };

                logger.WriteTo.Logger(lg =>
                    lg.WriteTo.Async(a =>
                        a.MSSqlServer(
                            configuration["Serilog:ConnectionString"],
                            sqlServerOptions,
                            columnOptions: columnOptions,
                            restrictedToMinimumLevel: configuration.GetValue<LogEventLevel>("Serilog:MinimumLevel")
                        )
                    )
                );
            });
        }
    }
}
